在 K8s 上,可經由容器或 POD 請求或使用的計算資源有記憶體和 CPU
。相互比較的話前者為不可壓縮資源,做一些伸縮操作可能會有問題,而後者事可壓縮資源,可以做伸縮的操作。
資源隔離是屬於容器級別,而資源藉由 requests
定義請求的可最小可用值,另一個 limits
用於限制資源最大可用值,如下圖所示。在 K8s 上,一個單位的 CPU 相當於虛擬機上的一顆 vCPU
或實體機上的一個 Hyperthread
(一個邏輯 CPU
),一個核心相當於 1000
個微核心所以200m
相當於 0.2
個核心。記憶體以 Ei
、Pi
、Ti
、Ki
等單位作為計算。
from "https://jaxenter.com/manage-container-resource-kubernetes-141977.html"
apiVersion: v1
kind: Pod
metadata:
name: stress-pod
labels:
app: test
spec:
containers:
- name: stress
image: ikubernetes/stress-ng
command: ["/usr/bin/stress-ng", "-c 1", "-m 1", "--metrics-brief"]
resources:
requests:
memory: "128Mi"
cpu: "200m"
配置清單上,POD 要求為容器要有 128Mi
記憶體和 5 分之 1 的 CPU
核心的最小資源。使用 -m 1
進行記憶體的壓測,滿載時盡可能占用 CPU
資源,同時間 -c 1
是對 CPU
進行壓測。
當上面的資源清單建立後,使用 exec
對容器執行 top
進行觀察。
$ kubectl exec stress-pod -- top
Mem: 2067432K used, 1976380K free, 3496K shrd, 102096K buff, 962844K cached
CPU: 99% usr 0% sys 0% nic 0% idle 0% io 0% irq 0% sirq
Load average: 1.04 0.29 0.12 3/509 13
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
8 7 root R 262m 7% 0 48% {stress-ng-vm} /usr/bin/stress-ng
6 1 root R 6900 0% 1 48% {stress-ng-cpu} /usr/bin/stress-ng
1 0 root S 6256 0% 0 0% /usr/bin/stress-ng -c 1 -m 1 --met
7 1 root S 6256 0% 0 0% {stress-ng-vm} /usr/bin/stress-ng
9 0 root R 1516 0% 0 0% top
測試用的行程 CPU
占用率為 48%
,stress-ng-vm
的記憶體占 262m(VSZ)
,其兩項資源都超出請求量,stress-ng
會在可用的範圍內盡量的占用相關的資源。內存為不可壓縮資源,因此 POD 在記憶體資源過載時可能會因 OOM
而被終止,而 CPU
則是會將多占用資源壓縮。因此,在 K8s 上運行關鍵應用程式相關的 POD 時需使用requests
定義最小可用資源。
limits
定義容器資源最大可用。定義此屬性可避免應用程式出現 Bug 導致資源長期被占用。下面的記憶體資源只要超出 limits
定義資源將被 OOM
終止。
apiVersion: v1
kind: Pod
metadata:
name: memleak-pod
labels:
app: mem
spec:
containers:
- name: simmemleak
image: saadali/simmemleak
resources:
requests:
memory: "64Mi"
cpu: "1"
limits:
memory: "64Mi"
cpu: "1"
$ kubectl get pod -o wide -w -l app=mem
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
memleak-pod 0/1 OOMKilled 1 22s 10.4.2.11 gke-cluster-1-default-pool-7dc8b11b-r7rg <none> <none>
memleak-pod 0/1 CrashLoopBackOff 1 25s 10.4.2.11 gke-cluster-1-default-pool-7dc8b11b-r7rg <none> <none>
memleak-pod 1/1 Running 2 28s 10.4.2.11 gke-cluster-1-default-pool-7dc8b11b-r7rg <none> <none>
memleak-pod 0/1 OOMKilled 2 29s 10.4.2.11 gke-cluster-1-default-pool-7dc8b11b-r7rg <none> <none>
與 requests
不同的是,limits
不會影響 POD
的調度結果,因此 limits
資源定義可大於節點所擁有的資源,當然過載使用還是會有容器會被 OOM
終止。
當我們設置上一章節所說的屬性,在資源吃緊的情況下,應該要用什麼方式進行先後順序的終止 POD
? K8s
無法自己做出決策,需借助 POD
的優先級別。依照 requests
和 limits
屬性,K8s
將 POD
歸類到三種 QoS
類別下
CPU
資源設置了具有相同值的 requests
和 limites
屬性,以及每個容器都為記憶體資源設置了具有相同值的 requests
和 limits
屬性的 POD
資源會自動歸屬此類,而這類的 POD
資源具有最高優先權CPU
或記憶體的 requests
屬性,但不滿足 Guaranteed
類別要求的 POD
資源自動歸屬此類,具有中等優先級別requests
或 limits
屬性的 POD
資源自對歸屬此類,優先級別最低每個運行的容器都有 OOM
得分,得分越高越會被優先終止。OOM
得分主要根據兩個維度進行計算,由 QoS
類別繼承而來的默認值和容器的可用記憶體資源比例。同等類別的 POD
資源的默認值相同,下面的程式碼從 pkg/kubelet/qos/policy.go
取得,它們定義的是各種類別的 POD
資源 OOM
調節(Adjust)值,即默認值。
在同一等級的優先級別下的 POD
資源在 OOM
時,與自己的 requests
相比,其記憶體占用比例最大的 POD
將被先終止。
const (
PodInfraOOMAdj int = -998
KubeletOOMScoreAdj int = -999
DockerOOMScoreAdj int = -999
KubeProxyOOMScoreAdj int = -999
guaranteedOOMScoreAdj int = -998
besteffortOOMScoreAdj int = 1000
)